#include	<stdio.h>
#include	<stdlib.h>
#include	<stdint.h>
#include	<strings.h>
#include	"player.h"
#include	"maze.h"
#include 	"protocol.h"
#include	"types.h"
#include	"update.h"

Team Teams[NUMTEAMS];
int numPlayers;

uint16_t
player_init(void)
{
  int i;
  for (i=0; i<NUMTEAMS; i++){
	Teams[i].playerListPtr = NULL;
	Teams[i].teamNo = (i == 0) ? PLAYER_ON_TEAM_1 : PLAYER_ON_TEAM_2;
	Teams[i].numPlayers = 0;
  }
  return 1;
}

Player *
player_add(Maze *m)
{
	numPlayers++;
	
	Player *p;
	uint16_t teamNo = (numPlayers % 2 == 1) ? 1 : 2;
	Team *t = (teamNo == 1) ? &Teams[0] : &Teams[1];
	
	if (t->numPlayers < PLAYERS_PER_TEAM_MAX) {
		p = (Player *)malloc(sizeof(Player));
		
		printf("player allocated\n");
	
		if (p) {
		
			t->numPlayers++;
			printf("\t\t t%i numplayers %i\n", teamNo, t->numPlayers);
			p->id = numPlayers;
			p->state = t->teamNo | PLAYER_AT_HOME;
			if ( teamNo == 1)
				p->state |= PLAYER_ON_TEAM_1; 
			else 
				p->state |= PLAYER_ON_TEAM_2;
			
	
			if (maze_player_add(m, p)){
			
				p->next = t->playerListPtr;
				t->playerListPtr = p;
			}
			else {
				free(p);
			}
		}
		//player_dump_team(teamNo);
		printf("about to return player\n");
	
		return p;
	}
	return NULL;
}

uint16_t
player_dump(Player *p)
{
	// CANNOT SWITCH next/state PRINTING ORDER: DON'T KNOW WHY
	fprintf(stderr, "%p: id=%ld *cell=%p *next=%p state=0x%lx, cell: ",
		p, p->id, p->cellPtr, p->next, p->state);
	
	maze_dump_cell(p->cellPtr);

	return 1;
}

uint16_t
player_dump_team(uint16_t teamNo)
{
	Player *p;
	uint16_t playerCnt = 0;
	
	Team *t = (teamNo == 1) ? &Teams[0] : &Teams[1];

	fprintf(stderr, "*team=%p *playerList=%p teamNo=%ld numPlayers=%ld\n",
		t, t->playerListPtr, t->teamNo, t->numPlayers);
	  
	for (p=t->playerListPtr; p != NULL; p=p->next) {
		player_dump(p);
		playerCnt++;
	}
	if (playerCnt != t->numPlayers){
		fprintf(stderr, "ERROR: playerCnt=%ld!=numPlayers=%ld\n", playerCnt, t->numPlayers);
		return 0;
	}
	return 1;
}

uint16_t
player_remove(Player *playerPtr)
{
	// get teamNo
	uint16_t teamNo = (PLAYER_BELONGS_TO_TEAM_1(playerPtr)) ? 1 : 2;
	Team *t = (teamNo == 1) ? &Teams[0] : &Teams[1];

	Player *p;
	Player *prev = NULL;
	
	for (p=t->playerListPtr; p != NULL; p=p->next){
		if (playerPtr == p){
			if (prev == NULL){
				Teams[teamNo].playerListPtr = p->next;
				free(p);
				printf("player removed=%p\n", p);
				return 1;
			}
			prev->next = p->next;
			free(p);
			printf("player removed=%p\n", p);
			return 1;
		}
		prev = p;
	}
	fprintf(stderr, "ERROR: player_remove: p=%p not found\n", playerPtr);
	return OBJECT_ERROR_ID;
}

int
player_tag(Maze *m, Cell *c, uint16_t teamNo){
	Team *t = (teamNo == 1) ? &Teams[0] : &Teams[1];
	
	Player *p;
	
	for (p=t->playerListPtr; p != NULL; p=p->next)
	{
	//	if (c == p->cellPtr)
		if ( c->pos.row == p->cellPtr->pos.row && c->pos.col == p->cellPtr->pos.col)
		{
			
	
			PLAYER_TOGGLE_IN_JAIL(p);
			 
			
			Cell * jcell = (Cell *) maze_find_jail(m, p);
			
			printf("\t\t player_tag Player %i is in jail row %i\n", p->id, jcell->pos.row);
			
			jcell->state |= HAS_A_PLAYER;
			jcell->extra |= teamNo;
			p->cellPtr = jcell;
			
			
						
			// send out the update for this tagged player
			CellUpdateBody cBody;
			cBody.pos = jcell->pos;
			cBody.cellType = 3;
			cBody.occupiedByPlayer = p->id;
			cBody.occupiedByObject = 0;
			
			// SEND UPDATE
			sendCellUpdateToAll(&cBody);
						
			
			printf("player_tag: p=%p tagged: row=%d, col=%d\n", p, jcell->pos.row, jcell->pos.col);
			return p->id;
		}
	}
	fprintf(stderr, "ERROR: player_tag: player at cell=%p not found\n", c);
	return (Player *) 0;
}

uint16_t
player_pickup (int sockfd, Player *p)
{
	Cell *c = p->cellPtr;

	CellUpdateBody cBody;
	cBody.pos = c->pos;
	cBody.cellType = 0;		// CAN ALSO BE HOME CELL: 2
	cBody.occupiedByPlayer = p->id;
	
	PlayerUpdateBody pBody;
	pBody.playerId = p->id;
	
	if (CELL_HAS_FLAG_1(c))
	{
		CELL_TOGGLE_HAS_FLAG(c);
		CELL_TOGGLE_HAS_FLAG_1(c);
		cBody.occupiedByObject = 0; // empty
		
		PLAYER_TOGGLE_HAS_FLAG_1(p);
		pBody.field = TEAM1_FLAG_ID;
		pBody.value = 1;
		
		return TEAM1_FLAG_ID;
	}
	else if (CELL_HAS_FLAG_2(c))
	{
		CELL_TOGGLE_HAS_FLAG(c);
		CELL_TOGGLE_HAS_FLAG_2(c);
		cBody.occupiedByObject = 0;
		
		PLAYER_TOGGLE_HAS_FLAG_2(p);
		pBody.field = TEAM2_FLAG_ID;
		pBody.value = 1;
		
		return TEAM2_FLAG_ID;
	}
	else if (CELL_HAS_BOMB_1(c))
	{
		CELL_TOGGLE_HAS_BOMBS(c);
		CELL_TOGGLE_HAS_BOMB_1(c);
		cBody.occupiedByObject = 0;
		
		PLAYER_TOGGLE_HAS_BOMBS(p);
		pBody.field = TEAM1_BOMBS_ID;
		pBody.value = 1;
		
		return TEAM1_BOMBS_ID;
	}
	else if (CELL_HAS_BOMB_2(c))
	{
		CELL_TOGGLE_HAS_BOMBS(c);
		CELL_TOGGLE_HAS_BOMB_2(c);
		cBody.occupiedByObject = 0;
		
		PLAYER_TOGGLE_HAS_BOMBS(p);
		pBody.field = TEAM2_BOMBS_ID;
		pBody.value = 1;
		
		return TEAM2_BOMBS_ID;
	}
	
	if ( pBody.field != OBJECT_ERROR_ID ) {
		// send cell updates and player updates to all
		sendCellUpdateToAll(&cBody);
		sendPlayerUpdateToAll(&pBody);
	}
	
	fprintf(stderr, "ERROR: player_pickup: c=%p has nothing to pick up\n", c);
	return OBJECT_ERROR_ID;
}

uint16_t
player_drop (int sockfd, Player *p)
{
	Cell *c = p->cellPtr;

	CellUpdateBody cBody;
	cBody.pos = c->pos;
	cBody.cellType = 0;		// CAN ALSO BE HOME CELL: 2
	cBody.occupiedByPlayer = p->id;
	
	PlayerUpdateBody pBody;
	pBody.playerId = p->id;
	
	if (PLAYER_POSSESS_FLAG_1(p))
	{
		CELL_TOGGLE_HAS_FLAG(c);
		CELL_TOGGLE_HAS_FLAG_1(c);
		cBody.occupiedByObject = TEAM1_FLAG_ID;
		
		PLAYER_TOGGLE_HAS_FLAG_1(p);		
		pBody.field = TEAM1_FLAG_ID;
		pBody.value = 0;
		
		return TEAM1_FLAG_ID;
	}
	else if (PLAYER_POSSESS_FLAG_2(p))
	{
		CELL_TOGGLE_HAS_FLAG(c);
		CELL_TOGGLE_HAS_FLAG_2(c);
		cBody.occupiedByObject = TEAM2_FLAG_ID;
		
		PLAYER_TOGGLE_HAS_FLAG_2(p);		
		pBody.field = TEAM2_FLAG_ID;
		pBody.value = 0;
		
		return TEAM2_FLAG_ID;
	}
	else if (PLAYER_POSSESS_BOMBS(p))
	{
		uint16_t isTeam1 = (p->id) % 2;
		
		if (isTeam1)
		{
			CELL_TOGGLE_HAS_BOMBS(c);
			CELL_TOGGLE_HAS_BOMB_1(c);
			cBody.occupiedByObject = TEAM1_BOMBS_ID;
		
			PLAYER_TOGGLE_HAS_BOMBS(p);
			pBody.field = TEAM1_BOMBS_ID;
			pBody.value = 0;
			
			return TEAM1_BOMBS_ID;
		}
		else
		{
			CELL_TOGGLE_HAS_BOMBS(c);
			CELL_TOGGLE_HAS_BOMB_2(c);
			cBody.occupiedByObject = TEAM2_BOMBS_ID;
		
			PLAYER_TOGGLE_HAS_BOMBS(p);
			pBody.field = TEAM2_BOMBS_ID;
			pBody.value = 0;
			
			return TEAM2_BOMBS_ID;
		}
	}
	
	if ( pBody.field != OBJECT_ERROR_ID ) {
		// send cell updates and player updates to all
		sendCellUpdateToAll(&cBody);
		sendPlayerUpdateToAll(&pBody);
	}
	
	fprintf(stderr, "ERROR: player_drop: p=%p has nothing to drop\n", p);
	return OBJECT_ERROR_ID;
}

